﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net;
using System.Web.Http;
using Newtonsoft.Json.Linq;
using TrinityAPI.Base.Models;
using TrinityAPI.Base.Tools;
using TrinityAPI.Tools;

namespace TrinityAPI.Controllers
{
    public class DefaultController : ApiController
    {
        [Route("{_service}")]
        [HttpGet]
        [HttpPost]
        [HttpPut]
        [HttpPatch]
        [HttpDelete]
        public JToken ApiGateway([FromUri] string _service, JToken request)
        {
            JToken header = APIHelper.GetRequestHeaders(Request);
            JToken query = APIHelper.GetRequestQuerys(Request);

            string apiFlag = (header as JObject).GetJsonObjectStringValue("trinity-method-flag");
            if (string.IsNullOrWhiteSpace(apiFlag))
                apiFlag = System.Configuration.ConfigurationManager.AppSettings[string.Format("{0}-method-flag", _service)];
            if (string.IsNullOrWhiteSpace(apiFlag))
                apiFlag = "method";
            string apiname = (query as JObject).GetJsonObjectStringValue(apiFlag);

            string versionFlag = (header as JObject).GetJsonObjectStringValue("trinity-version-flag");
            if (string.IsNullOrWhiteSpace(versionFlag))
                versionFlag = System.Configuration.ConfigurationManager.AppSettings[string.Format("{0}-version-flag", _service)];
            if (string.IsNullOrWhiteSpace(versionFlag))
                versionFlag = "version";
            string version = (query as JObject).GetJsonObjectStringValue(versionFlag);

            if (string.IsNullOrWhiteSpace(apiname))
            {
                apiname = _service;
                _service = null;
            }

            return ApiGateway(_service, version, apiname, request);
        }

        [Route("{_service}/{_version}")]
        [HttpGet]
        [HttpPost]
        [HttpPut]
        [HttpPatch]
        [HttpDelete]
        public JToken ApiGateway([FromUri] string _service, [FromUri] string _version, JToken request)
        {
            JToken header = APIHelper.GetRequestHeaders(Request);
            JToken query = APIHelper.GetRequestQuerys(Request);

            string apiFlag = (header as JObject).GetJsonObjectStringValue("trinity-method-flag");
            if (string.IsNullOrWhiteSpace(apiFlag))
                apiFlag = System.Configuration.ConfigurationManager.AppSettings[string.Format("{0}-method-flag", _service)];
            if (string.IsNullOrWhiteSpace(apiFlag))
                apiFlag = "method";
            string apiname = (query as JObject).GetJsonObjectStringValue(apiFlag);

            if (string.IsNullOrWhiteSpace(apiname))
            {
                apiname = _version;
                _version = null;
            }

            return ApiGateway(_service, _version, apiname, request);
        }

        [Route("{_service}/{_version}/{_apiname}")]
        [HttpGet]
        [HttpPost]
        [HttpPut]
        [HttpPatch]
        [HttpDelete]
        public JToken ApiGateway([FromUri] string _service, [FromUri] string _version, [FromUri] string _apiname, JToken request)
        {
            return ApiGateway(_service, _version, _apiname, null, request);
        }

        [Route("{_service}/{_version}/{_apiname}/{_id}")]
        [HttpGet]
        [HttpPost]
        [HttpPut]
        [HttpPatch]
        [HttpDelete]
        public JToken ApiGateway([FromUri] string _service, [FromUri] string _version, [FromUri] string _apiname, [FromUri] string _id, JToken request)
        {
            var settings = APIHelper.APIInit(_service, _version, _apiname);
            if (settings == null)
                throw new HttpResponseException(HttpStatusCode.NotFound);

            JObject dataset = null;
            JObject responseConfigs = settings.GetJsonObject("response");

            try
            {
                DateTime time = DateTime.Now;
                JToken header = APIHelper.GetRequestHeaders(Request);
                JToken query = APIHelper.GetRequestQuerys(Request, _id);
                string rawQuery = Request.RequestUri.Query.TrimStart('?');
                string rawRequest = Request.Content.ReadAsStringAsync().Result;
                dataset = APIHelper.DatasetInit(settings, header, query, request, APIHelper.GetRequestUri(Request), Request.Method.Method, rawQuery, rawRequest);
                LogHelper.Debug(string.Format("{0} initialize dataset takes time:{1}ms", APIContext.ApiFullName, (DateTime.Now - time).TotalMilliseconds));

                dataset = APIHelper.DoProcess(settings, dataset);

                var data = responseConfigs.GetJsonObjectValue("data");
                var headers = responseConfigs.GetJsonObject("headers");
                APIContext.ResponseHeaders = Utils.ParseObject(headers, dataset) as JObject;
                return APIHelper.ParseResponse(data, dataset);
            }
            catch (Exception ex)
            {
                string log = null;
                BaseException exception = null;
                if (ex is ConfigException)
                {
                    log = "{0} config exception";
                    exception = ExceptionHelper.GenException(ErrorCode.E000000002, ex.Message);
                }
                else if (ex is BaseException)
                {
                    log = "{0} base exception";
                    exception = (BaseException)ex;
                }
                else if (ex.Message != null && ex.Message.StartsWith("@"))
                {
                    log = "{0} base exception";
                    exception = ExceptionHelper.GenException(ex.Message);
                }
                else
                {
                    log = "{0} unknown exception";
                    exception = ExceptionHelper.GenException(ErrorCode.E000000001);
                }
                LogHelper.Error(string.Format(log, APIContext.ApiFullName), ex);

                if (exception == null)
                    exception = new BaseException();

                if (dataset == null)
                    dataset = new JObject();

                dataset["error"] = new JObject() { { "code", exception.Code }, { "message", exception.Message } };

                var error = responseConfigs.GetJsonObjectValue("error");
                error = APIHelper.ParseResponse(error, dataset);

                if (error == null)
                {
                    error = new JObject() {
                        { "status", "failure" },
                        { "code", exception.Code },
                        { "message", exception.Message }
                    };
                }

                string errorContentType = responseConfigs.GetJsonObjectStringValue("errorcontenttype");
                if (!string.IsNullOrWhiteSpace(errorContentType))
                    APIContext.ResponseContentType = errorContentType;

                return error;
            }
        }
    }
}
